package DyingBaby.backend.dm;

import DyingBaby.backend.dm.dataItem.DataItem;
import DyingBaby.backend.dm.logger.Logger;
import DyingBaby.backend.dm.page.PageOne;
import DyingBaby.backend.dm.pageCache.PageCache;
import DyingBaby.backend.tm.TransactionManager;

/**
 * DataManager 接口定义了数据管理器的核心功能，负责管理数据的物理存储和检索。
 * 它是数据库系统的核心组件，协调页面缓存、日志系统和事务管理器的交互。
 */
public interface DataManager {
    /**
     * 根据唯一标识符读取数据项
     * @param uid 数据项的唯一标识符
     * @return 读取到的数据项
     * @throws Exception 读取过程中可能发生的异常
     */
    DataItem read(long uid) throws Exception;

    /**
     * 插入新数据
     * @param xid 事务ID
     * @param data 要插入的数据字节数组
     * @return 新插入数据项的唯一标识符
     * @throws Exception 插入过程中可能发生的异常
     */
    long insert(long xid, byte[] data) throws Exception;

    /**
     * 关闭数据管理器，释放资源
     */
    void close();

    // 静态工厂方法
    /**
     * 从空文件创建并初始化一个新的DataManager实例
     * @param path 数据库文件路径
     * @param memory 分配给页面缓存的内存大小
     * @param tm 事务管理器实例
     * @return 新创建的DataManager实例
     */
    public static DataManager create(String path, long memory, TransactionManager tm) {
        // 创建页面缓存
        PageCache pc = PageCache.create(path, memory);
        // 创建日志记录器
        Logger lg = Logger.create(path);

        // 创建DataManager实现实例
        DataManagerImpl dm = new DataManagerImpl(pc, lg, tm);
        // 初始化第一页（特殊页面，通常包含数据库元数据）
        dm.initPageOne();
        return dm;
    }

    /**
     * 打开已存在的数据库文件并创建DataManager实例
     * @param path 数据库文件路径
     * @param memory 分配给页面缓存的内存大小
     * @param tm 事务管理器实例
     * @return 创建的DataManager实例
     */
    public static DataManager open(String path, long memory, TransactionManager tm) {
        // 打开现有的页面缓存
        PageCache pc = PageCache.open(path, memory);
        // 打开现有的日志记录器
        Logger lg = Logger.open(path);
        // 创建DataManager实现实例
        DataManagerImpl dm = new DataManagerImpl(pc, lg, tm);

        // 检查第一页（特殊页面，通常包含数据库元数据）的有效性，如果不有效则进行恢复操作
        if(!dm.loadCheckPageOne()) {
            Recover.recover(tm, lg, pc);
        }

        // 填充页面索引，建立空闲页面管理结构
        dm.fillPageIndex();
        // 设置第一页的版本控制信息为"已打开"
        PageOne.setVcOpen(dm.pageOne);
        // 将修改后的第一页刷新到磁盘
        dm.pc.flushPage(dm.pageOne);

        return dm;
    }
}
